home *** CD-ROM | disk | FTP | other *** search
/ CD Actual 9 / CDACTUAL9.iso / share / Dos / VARIOS / pascal / SWAG9605.DDD / 0021_Partial JPEG File info.pas < prev    next >
Encoding:
Pascal/Delphi Source File  |  1996-05-31  |  22.8 KB  |  760 lines

  1. {$A+,B-,D+,E+,F-,G+,I+,L+,N-,O-,P-,Q+,R+,S+,T-,V-,X-}
  2. {:
  3. PREFACE:
  4.  
  5. A basic jpeg/jfif file is compossed of subsections which I will call
  6. segments. Each segment has a header ID. Some headers have information
  7. blocks following the header, while some don not. Basically, the
  8. stucture can be thought of as follows:  (ID [info.], ... , ID [info.]).
  9. So, a segment can be compossed of only a header or a header with
  10. data following.
  11.  
  12. Unlike most structures, the segments do not have a predefined order;
  13. therefor, it is maditory to read the ID header first then treat the
  14. following data occurding to its header. Remember, certain headers
  15. do not have any following data - I will label these in the code.
  16.  
  17. The only predifined structure that a jpeg/jfif has is the following:
  18. The file starts with the SOI(start of information) header and is
  19. followed by the app0 segment. Followed by any number of other segments,
  20. followed by the EOI(end of information) segment.
  21.  
  22. arrangment:  SOI (start of information)
  23.              app0
  24.              [ ... unknown ... ]
  25.              EOI (end of information)
  26.  
  27.  
  28. The usual arrangment that I have found in most jpeg/jfif files is as
  29. follows:
  30.              SOI    (start of information)
  31.              app0   (JFIF label w/ image description)
  32.              DQT    (Define quantization table)
  33.              sof0   (start of frame)
  34.              DHT    (Define huffman table)
  35.              DHT    (Define huffman table)
  36.              DHT    (Define huffman table)
  37.              DHT    (Define huffman table)
  38.              SOS    (Start of scan)
  39.        NOTE: dqt,sof0, & dht don't always appear in this order.
  40.  
  41. Description:
  42.     SOI:  just a "dumb" header - no information follows.
  43.  
  44.     app0: for jfif files - JFIF id, version #, unit,
  45.           x & y density, thumbnail info & thumbnail (if any)
  46.           SEE app0_info TYPE
  47.  
  48.     DQT:  defines 8x8 table used for quantization
  49.  
  50.     sof0: image height & width & color components
  51.           jfif support (1) Y or (3) Y Cb Cr
  52.           a yuv_to_rbg function is in this unit.
  53.  
  54.     DHT: Set's up all the huffman tables used to decompress
  55.          the image.
  56.  
  57.     SOS: defines AC & DC huffman tables to use for each color component
  58.  
  59. Headers:
  60. Headers are 2 bytes, in hexidecimal "FF" followed by the ID byte.
  61. For ease of tranlastion, I have set up a list of constants to
  62. determine the header ID (eg. sof0,dht,sos,..., ect.)
  63. ALL headers with infomation following have a word that tells the
  64. length of the data following. The word is not in the intel lo-hi
  65. format, so I included a HI_LO function for translation.
  66. To read any segment you only need to the following:
  67.    Read the header, identify it.
  68.    Read the hi-lo word for length, translate HI_LO().
  69.    Read "length" bytes of data.
  70.    NOTE: Not all headers have a length or data block.
  71.  
  72.  
  73. THIS FILE----------------------------------------------
  74.  
  75. This unit is design specifically for debuging and block testing. What
  76. this means is that no actual file needs to be used to test and debug
  77. each segment handling procedure. The driver file is responsible for
  78. header identification, file reading, and so on.
  79.  
  80. To process an information block, read the header & identify it.
  81. Read the length, subtract 2 from it and save it. Read "length" bytes
  82. into a block (array of bytes). Now, give the appropriete procedure
  83. the block, length, and a predefined type (Quan_tables, Huff_tables,
  84. app0_info, frame_0, scan_info).
  85.  
  86. }
  87.  
  88. UNIT jpegsegm; { see TEST program at the bottom ! }
  89.  
  90. INTERFACE
  91.   CONST TEM  = $01;            {unknown}
  92.       SOF0 = $c0;            {start of FRAME}
  93.       SOF1 = $c1;            {""""""""""""""}
  94.       SOF2 = $c2;            {following SOF usually unsupported}
  95.       SOF3 = $c3;
  96.       SOF5 = $c2;
  97.       SOF6 = $c6;
  98.       SOF7 = $c7;
  99.       SOF9 = $c9;            {sof9 : for arithmetic coding - taboo!}
  100.       SOF10= $ca;
  101.       SOF11= $cb;
  102.       SOF13= $cd;
  103.       SOF14= $ce;
  104.       SOF15= $cf;
  105.       DHT  = $c4;            {Define huffman Table}
  106.       JPG  = $c8;            {undefined/ reserved =Error?}
  107.       DAC  = $cc;            {define arithmetic table UNSUPORTED }
  108.       RST0 = $d0;            {Used for resync [?] ignored}
  109.       rst1 = $d1;
  110.       rst2 = $d2;
  111.       rst3 = $d3;
  112.       rst4 = $d4;
  113.       rst5 = $d5;
  114.       rst6 = $d6;
  115.       rst7 = $d7;
  116.       SOI  = $d8;            {start of image}
  117.       EOI  = $d9;            {end   of image}
  118.       SOS  = $da;            {start of scan }
  119.       DQT  = $db;            {Define Quantization Table}
  120.       DNL  = $dc;            {unknown -usually unsupported}
  121.       DRI  = $dd;            {Define Restart Interval}
  122.       DHP  = $de;            {ignore }
  123.       EXP  = $df;
  124.       APP0 = $e0;            {JFIF app0 segment marker}
  125.       APP15= $ef;            {ignore}
  126.       JPG0 = $f0;
  127.       JPG13= $fd;
  128.       COM  = $fe;            {Comment}
  129.  
  130.   {: Do App0 :}
  131.  
  132.   TYPE app0_info = record
  133.                    revision   : record
  134.                                   major,         {>= 1}
  135.                                   minor : byte;
  136.                                 end;
  137.                    XY_density : byte;
  138.                    X,Y        : word;
  139.                    thumb_X,
  140.                    thumb_y    : byte;
  141.                  end;
  142.  
  143.   {: Define Quantization Table :}
  144.  
  145.   TYPE Q_byte      = array[0..7,0..7] of byte;
  146.        Q_word      = array[0..7,0..7] of word;
  147.        Q_type_type = (bit_8,bit_16);
  148.        Quan_range = 0..3;
  149.        Quan_tables = array[Quan_range] of
  150.                      record
  151.                       Valid  : Boolean;
  152.                       Q_TYPE : Q_type_type;
  153.                       Q      : record
  154.                                  case integer of
  155.                                   1 : (Q_byte : array[0..7,0..7] of byte);
  156.                                   2 : (Q_word : array[0..7,0..7] of word);
  157.                                  end;
  158.                      end;
  159.        One_quan_table = record
  160.                         case integer of
  161.                          1 : (Q_int  : array[0..7,0..7] of Integer);
  162.                          2 : (Q_long : array[0..7,0..7] of Longint);
  163.                         end;
  164.  
  165.   {: Define Huffman Table :}
  166.  
  167.   TYPE huff_type   = (AC, DC);
  168.        Huff_range  = 0..3;
  169.        Huff_tables = array[huff_type] of
  170.                      record
  171.                        Table : array[Huff_range] of
  172.                        record
  173.                          valid     : boolean;
  174.                          H_type    : huff_type;
  175.                          Max_code  : array[1..16] of byte;
  176.                          H         : array[1..257] of
  177.                                      record
  178.                                        len  : byte;
  179.                                        code : word;
  180.                                        sym  : byte;
  181.                                      end;
  182.                        end;
  183.                      end;
  184.  
  185.   {: Start of Frame :}
  186.  
  187.   type  id_type   = (no_id, Y_, CB_, CR_, I_, Q_);
  188.         comp_type = (grey, no_comp, color);
  189.         frame_0 = record
  190.                    precision    : byte;
  191.                    image_height : word;
  192.                    image_width  : word;
  193.                    comp_num     : comp_type;
  194.                    factor : array[1..3] of
  195.                             record
  196.                               id    : id_type;
  197.                               horz_factor   : byte;
  198.                               vert_factor   : byte;
  199.                               Q_num : byte;
  200.                             end;
  201.                   end;
  202.  
  203.   {: Start of Scan :}
  204.  
  205.   type comp_range = 1..4;
  206.        scan_info = record
  207.                      comp_num : comp_range;
  208.                      Each : array[comp_range] of
  209.                             record
  210.                               valid   : boolean;
  211.                               id      : id_type;
  212.                               huff_ac : huff_range;
  213.                               huff_dc : huff_range;
  214.                             end;
  215.                    end;
  216.  
  217.  
  218.   PROCEDURE DO_sof0(VAR block : array of byte; Len : word;
  219.                     VAR Frame : frame_0);
  220.   Function  DO_app0(VAR block : array of byte; Len : word;
  221.                    VAR info : app0_info ) : boolean;
  222.   PROCEDURE DO_DQT(VAR block : array of byte; Len : word;
  223.                  VAR All_DQT : Quan_tables);
  224.   PROCEDURE DO_sos(VAR block : array of byte; Len : word;
  225.                    Var Scan : Scan_info);
  226.   PROCEDURE DO_DHT(VAR block : array of byte; Len : word;
  227.                  VAR all_dht : huff_tables);
  228.  
  229.   PROCEDURE DO_DRI; {unknown}
  230.  
  231.   procedure DeQuantize( VAR Q : Quan_tables; Num : byte;
  232.                         VAR in_q : one_quan_table);
  233.   procedure IDCT(VAR one : one_quan_table);
  234.  
  235.   FUNCTION  HI_LO(inw : word) : word;
  236.  
  237. IMPLEMENTATION
  238.  
  239. {::::::::::::::::::::::::::::::::::}
  240. {: Change a HI-LO word to LO-HIGH :}
  241. {::::::::::::::::::::::::::::::::::}
  242.  
  243.   FUNCTION  HI_LO(inw : word) : word;
  244.   var dwd : word;
  245.   begin
  246.     dwd := 0;
  247.     dwd := inw SHR 8;
  248.     dwd := dwd OR (inw SHL 8);
  249.     Hi_lo := dwd;
  250.   end;
  251.  
  252.  
  253.   procedure yuv_to_RGB( Y,CB,Cr : integer; VAR R,G,B : byte);
  254.   begin
  255.     r := trunc(y + 1.402 *(Cr-128));
  256.     g := trunc(y - 0.34414 * (cb-128) - 0.71414*(cr-128));
  257.     b := trunc(y + 1.772*(Cb-128));
  258.   end;
  259.  
  260. {::::::::::::::}
  261. {: Dequantize :}
  262. {::::::::::::::}
  263. {: component wise multiplication of 2 8x8 matricies :}
  264. {: where b[x,y] = q[x,y] * a[x,y]                   :}
  265. {check}
  266.  
  267.   procedure DeQuantize( VAR Q : Quan_tables; Num : byte;
  268.                         VAR in_q : one_quan_table);
  269.   var i,j : byte;
  270.   begin
  271.     with Q[num] do begin
  272.          case q_type of
  273.           bit_8  : begin
  274.                     for I := 0 to 7 do
  275.                         for j := 0 to 7 do
  276.                         in_q.q_int[i,j] := in_q.q_int[i,j] * Q.Q_byte[i,j];
  277.                    end;
  278.           bit_16 : begin
  279.                     for I := 0 to 7 do
  280.                         for j := 0 to 7 do
  281.                         in_q.q_long[i,j] := in_q.q_long[i,j] * Q.Q_word[i,j];
  282.                    end;
  283.          end;
  284.     end;
  285.   end;
  286.  
  287. {:::::::::::::::}
  288. {: Inverse DCT :}
  289. {:::::::::::::::}
  290.                   {u}   {v}
  291.   const C : array [0..7,0..7] of real =
  292.   ((0.5, 0.707106781188, 0.707106781188, 0.707106781188,
  293.     0.707106781188, 0.707106781188, 0.707106781188, 0.707106781188),
  294.    (0.707106781188, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0),
  295.    (0.707106781188, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0),
  296.    (0.707106781188, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0),
  297.    (0.707106781188, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0),
  298.    (0.707106781188, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0),
  299.    (0.707106781188, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0),
  300.    (0.707106781188, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0));
  301.  
  302.   procedure IDCT(VAR one : one_quan_table);
  303.   var u,v,
  304.       x,y  : byte;
  305.       suma,
  306.       sumb : real;
  307.       temp_q : one_quan_table;
  308.   begin
  309.     for y := 0 to 7 do begin
  310.         for x := 0 to 7 do begin
  311.   
  312.             suma := 0;
  313.             for u := 0 to 7 do begin
  314.                 sumb := 0;
  315.                 for v := 0 to 7 do begin
  316.                     sumb := sumb + (c[u,v] * one.q_int[u,v] *
  317.                                     cos( ((2*x+1) * u * pi) / 16 ) *
  318.                                     cos( ((2*y+1) * v * pi) / 16 ));
  319.                 end;
  320.                 suma := suma + sumb;
  321.             end;
  322.             suma := suma * 0.25;
  323.             temp_q.q_int[x,y] := trunc(suma) + 120;
  324.         end;
  325.     end;
  326.   
  327.     for y := 0 to 7 do begin
  328.         for x := 0 to 7 do begin
  329.             one.q_int[x,y] :=  temp_q.q_int[x,y];
  330.         end;
  331.     end;
  332.  
  333.   end;
  334.  
  335. {:::::::::::::::::::::::}
  336. {: JFIF Segment marker :}
  337. {:::::::::::::::::::::::}
  338.  
  339. {: IF JFIF+#0 does not follow the header, then skip by LEN - 7.  :}
  340. {: Two bytes have ben passed to read LEN, and five to read JFIF0 :}
  341.  
  342.   Function DO_app0(VAR block : array of byte; Len : word;
  343.                    VAR info : app0_info ) : boolean;
  344.   const string_len = 5;
  345.   VAR Jfif_ID : STRING; {JFIF + #0}
  346.       Cur    : word;
  347.   BEGIN
  348.     cur := 0;
  349.   
  350.     move(block[cur], Jfif_ID[1], string_len); Jfif_ID[0]:= chr(string_len);
  351.     inc(cur, string_len);
  352.     Len := Len - string_len;
  353.   
  354.     IF  (Jfif_ID<>('JFIF'+#0)) then begin
  355.         {Bskip(F, len);}
  356.         do_app0 := false;
  357.     end ELSE BEGIN
  358.   
  359.   
  360.         move(block[cur], Info, SizeOf(Info));
  361.         inc(cur, SizeOf(Info));
  362.         dec(Len, SizeOf(Info));
  363.         if  info.revision.major < 1 then begin
  364.             {writeln(DE,' Invalid Revision version.');}
  365.             exit;
  366.         end;
  367.   
  368.   
  369.   
  370.         IF  (info.thumb_x * info.thumb_Y * 3 <> 0) then begin
  371.             {Bskip(f, info.thumb_x * info.thumb_Y * 3);}
  372.             {the thumbnail N bytes; RGB 24bit W*H*3}
  373.             len := len - (info.thumb_x * info.thumb_Y * 3);
  374.         end;
  375.         if  Len = 0 then
  376.             do_app0 := True
  377.         else
  378.             do_app0 := False;
  379.     END;
  380.  
  381.   END;
  382.  
  383. {:::::::::::::::::::::::::::::}
  384. {: Define Quantization Table :}
  385. {:::::::::::::::::::::::::::::}
  386.  
  387.  
  388. PROCEDURE DO_DQT(VAR block : array of byte; Len : word;
  389.                    VAR All_DQT : Quan_tables);
  390.   {might work in all cases}
  391.   VAR k,l  : byte;
  392.  
  393.       QT_info : byte;
  394.       QT_prec : byte;
  395.       QT_num  : byte;
  396.   
  397.       Cur     : word;
  398.   BEGIN
  399.     Cur := 0;
  400.   
  401.     repeat
  402.       {::::::::::::::::}
  403.       {: Read QT Info :}
  404.       {::::::::::::::::}
  405.   
  406.       { Set all_dqt[ QT_num ]       }
  407.       {                      .Valid }
  408.       {                      .type  }
  409.   
  410.       Qt_info := Block[cur]; Inc(cur);  Len := Len -1;
  411.       QT_num  := Qt_info and $0F;
  412.       QT_prec := (Qt_info and $f0) shr 4;
  413.   
  414.       {:::::::::::::::::::}
  415.       {: Read in Q table :}
  416.       {:::::::::::::::::::}
  417.   
  418.       { Set all_dqt[ QT_num ]       }
  419.       {                      .Q[]   }
  420.   
  421.       with all_dqt[ QT_num ] do begin
  422.            valid := True;
  423.            case QT_prec of
  424.             0 : begin
  425.                   Q_type := (bit_8);
  426.                   move(block[cur], Q.Q_byte, Sizeof(Q_byte));
  427.                   inc(cur, sizeof(Q_byte));
  428.                   Len := Len -  SizeOf(Q_byte);
  429.   
  430.                 end;
  431.             1 : begin
  432.                   Q_type := (bit_16);
  433.                   move(block[cur], Q.Q_word, Sizeof(Q_word));
  434.                   inc(cur, sizeof(Q_word));
  435.                   Len := Len -  SizeOf(Q_word);
  436.                 end;
  437.             ELSE BEGIN
  438.                    {writeln(DE,'Invalid QT_precison in DO_DQT');}
  439.                    halt(1);
  440.                  END;
  441.             END;
  442.       END;
  443.     until (len = 0);
  444.   END;
  445.   
  446.  
  447.  
  448.   {:::::::::::::::::}
  449.   {: Start Of Scan :}
  450.   {:::::::::::::::::}
  451.  
  452.   PROCEDURE do_sos(VAR block : array of byte; Len : word;
  453.                    Var Scan : Scan_info);
  454.   var k,dw : word;   Done: boolean;
  455.       db       : byte;
  456.       Cur      : word;
  457.   begin
  458.     Cur := 0;
  459.     with Scan do begin
  460.          Comp_num := Block[cur]; inc(cur); dec(len);
  461.          for K := 1 to Comp_num do begin
  462.              Each[ K ].valid := true;
  463.  
  464.              Each[ K ].ID := id_type(block[cur]); inc(cur); dec(len);
  465.  
  466.              DB := block[cur]; inc(cur); dec(len);
  467.              Each[ K ].huff_ac := db and $f;
  468.              Each[ K ].huff_dc := (db and $f0) shr 4;
  469.          end;
  470.     end;
  471.   end;
  472.  
  473.  
  474. {::::::::::::::::::::::::}
  475. {: Define Huffman Table :}
  476. {::::::::::::::::::::::::}
  477.  
  478.   CONST Huff_mask : array[1..16] of
  479.                   word =(  $01,  $03,  $07,  $0f,
  480.                            $1f,  $3f,  $7f,  $ff,
  481.                          $01ff,$03ff,$07ff,$0fff,
  482.                          $1fff,$3fff,$7fff,$ffff);
  483.  
  484.   PROCEDURE DO_DHT(VAR block : array of byte; Len : word;
  485.                    VAR all_dht : huff_tables);
  486.   
  487.   VAR DW : Word;
  488.     j,k,l,
  489.       cur     : byte;
  490.       Sum     : word;
  491.       Size    : byte;
  492.       code    : word;
  493.       lenths  : array[1..16] of byte;
  494.   
  495.       HT_info : byte;
  496.       HT_num  : byte;
  497.       HT_type : byte;
  498.       {DW      : word;}
  499.   BEGIN
  500.   
  501.     Cur := 0;
  502.     Repeat
  503.       {::::::::::::::::::}
  504.       {: Read Huff Info :}
  505.       {::::::::::::::::::}
  506.   
  507.       { SET ALL_DHT[HT_NUM]          }
  508.       {                   .Valid     }
  509.       {                   .H_type    }
  510.   
  511.       ht_info := block[cur]; inc(cur);
  512.       Len := Len - 1;
  513.       HT_num  := HT_info and $F;
  514.       HT_type := (HT_info and $F0) shr 4;
  515.   
  516.       with all_dht[ huff_type(HT_TYPE) ].Table[ HT_num ] do begin
  517.            Valid  := True;
  518.            case HT_type of
  519.             0 : H_type := DC;
  520.             1 : H_type := AC;
  521.            else begin
  522.                   {writeln(DE,'Invalid Huffman table type.');}
  523.                   halt(1);
  524.                 end;
  525.            end;
  526.       end;
  527.  
  528.       {$IFDEF DEBUG } writeln(DE,'-- HT num  : ',HT_num);
  529.                       writeln(DE,'-- HT type : ',HT_type);
  530.       {$ENDIF}
  531.   
  532.       {::::::::::::::::::}
  533.       {: Read in lenths :}
  534.       {::::::::::::::::::}
  535.   
  536.       move(block[cur], Lenths[1], 16); inc(cur,16);
  537.       Len := Len - 16;
  538.   
  539.       {::::::::::::::::::::::}
  540.       {: Read in symbols    :}
  541.       {: partially borrowed :}
  542.       {::::::::::::::::::::::}
  543.   
  544.       { SET ALL_DHT[HT_NUM]          }
  545.       {                   .Valid     }
  546.       {                   .H[].Len   }
  547.       {                   .H[].Sym   }
  548.       {                   .Max_code  }
  549.   
  550.   
  551.   
  552.       with all_dht[ huff_type(HT_TYPE) ].Table[ HT_num ] do begin
  553.            L   := 1;
  554.            sum := 0;
  555.            For k := 1 to 16 do begin
  556.   
  557.                Sum := Sum + lenths[k];
  558.                for j := 1 to lenths[k] do begin      {: if 0 then skipped   :}
  559.                    H[L] .len := K;
  560.   
  561.                    H[L] .sym := block[cur];inc(cur); {: read in symbols     :}
  562.                                                      {: as we go            :}
  563.                    Len := Len - 1;
  564.                    inc(L);
  565.                end;
  566.                Max_code[k] := L;
  567.            end;
  568.            H[L] .len := 0;                        {: Last will have Zero :}
  569.       end;
  570.   
  571.   
  572.       {::::::::::::::::::::::::}
  573.       {: Create huffman Codes :}
  574.       {: partially borrowed   :}
  575.       {::::::::::::::::::::::::}
  576.  
  577.       { Set all_dht[HT_NUM]. H[].CODE }
  578.  
  579.  
  580.       with all_dht[ huff_type(HT_TYPE) ].Table[ HT_num ] do begin
  581.            L    := 1;
  582.            Size := H[1].len;
  583.            code := 0;
  584.            while (H[L].len <> 0) do begin
  585.                  while (H[L].len = Size) do begin
  586.                        H[L].code := Huff_mask[ H[L].Len] and Code;
  587.                        inc(L);
  588.                        inc(Code);
  589.                  end;
  590.                  code := code shl 1;
  591.                  inc(Size);
  592.            end;
  593.       end;
  594.   
  595.     until (Len = 0);
  596.   END;
  597.   
  598.  
  599.   PROCEDURE DO_DRI;
  600.   VAR Len, dw2,dw: word;
  601.   BEGIN
  602.   END;
  603.  
  604.  
  605.  
  606.  
  607.  
  608.   PROCEDURE DO_sof0(VAR block : array of byte; Len : word;
  609.                     VAR Frame : frame_0);
  610.   VAR K,dw : word;
  611.       db    : byte;
  612.  
  613.       Cur      : word;
  614.   BEGIN
  615.     cur := 0;
  616.  
  617.     with frame do begin
  618.          precision    := block[cur]; inc(cur); dec(len);
  619.  
  620.          move(block[cur], image_height, 2); inc(cur,2); dec(len,2);
  621.          image_height := hi_lo(image_height);
  622.  
  623.          move(block[cur], image_width, 2); inc(cur,2); dec(len,2);
  624.          image_width := hi_lo(image_width);
  625.  
  626.          dw := block[cur]; inc(cur); dec(len);
  627.          case dw of
  628.           1 : begin
  629.                 comp_num := grey;
  630.               end;
  631.           3 : begin
  632.                 comp_num := color;
  633.               end;
  634.          else begin
  635.                 writeln('SOF0: component not supported.');
  636.                 halt(1);
  637.               end;
  638.          end;
  639.  
  640.          for K := 1 to DW do begin
  641.              with frame.factor[K] do begin
  642.                   db := block[cur]; Inc(cur); dec(len);
  643.                   case db of
  644.                    1 : ID := Y_;
  645.                    2 : ID := CB_;
  646.                    3 : ID := CR_;
  647.                    4 : ID := I_;
  648.                    5 : ID := Q_;
  649.                   end;
  650.  
  651.                   db := block[cur]; Inc(cur); dec(len);
  652.                   horz_factor := db and $f;
  653.                   vert_factor := (db and $f0) shr 4;
  654.                   q_num       := block[cur]; Inc(cur); dec(len);
  655.              end; {with}
  656.          end;
  657.     end;
  658.   END;
  659. END.
  660.  
  661. { ---------------------   TEST PROGRAM -------------------- }
  662.  
  663. {$A+,B-,D+,E+,F-,G+,I-,L+,N-,O-,P-,Q+,R+,S+,T-,V-,X-}
  664.  
  665. program tjpeg;
  666. uses jpegsegm;
  667.  
  668.  
  669. var f      : file;
  670.     dw,
  671.     length : word;
  672.     db     : byte;
  673.     darray : array[0..2047] of byte;
  674.     ai     : app0_info;
  675.     qts    : quan_tables;
  676.     hts    : huff_tables;
  677.     si     : scan_info;
  678.     f0     : frame_0;
  679. begin
  680.   {:::::::::::::::::::::::::::::}
  681.   {: Required JPEG/JFIF format :}
  682.   {:::::::::::::::::::::::::::::}
  683.  
  684.   {: open file :}
  685.   assign(F, paramstr(1)); filemode := 0;
  686.   reset(f,1);
  687.   if  (IOResult <> 0) then begin
  688.       writeln('Syntax:  tjepg [filename]');
  689.       writeln('Unable to open file: ', paramstr(1));
  690.       halt(1);
  691.   end;
  692.  
  693.   {: read soi header :}
  694.   blockread(f, db, 1);
  695.   blockread(f, db, 1);
  696.   if  (db <> SOI) then begin
  697.       writeln('File is missing required SOI header.');
  698.       halt(1);
  699.   end;
  700.  
  701.   {: read app0 block length :}
  702.   blockread(f, db, 1);
  703.   blockread(f, db, 1);
  704.   if  (db <> app0) then begin
  705.       writeln('File is missing reqired app0 header.');
  706.       halt(1);
  707.   end;
  708.  
  709.   {: read app0 block :}
  710.   blockread(f, length, 2);
  711.   length := hi_lo(length) - 2;
  712.  
  713.   blockread(f, darray, length);
  714.   if  not do_app0( darray, length, ai) then begin
  715.       writeln('Missing JFIF marked app0 segment.');
  716.       halt(1);
  717.   end;
  718.  
  719.  
  720.   {::::::::::::::::::::::::::::::}
  721.   {: process remaining segments :}
  722.   {::::::::::::::::::::::::::::::}
  723.   repeat
  724.     blockread(f, db, 1, dw); {must be FF} if dw <> 1 then halt(2);
  725.     blockread(f, db, 1, dw); {header ID } if dw <> 1 then halt(2);
  726.  
  727.     blockread(f, length, 2, dw);
  728.     length := hi_lo(length) - 2;
  729.     if  db in [dht,dqt,sof0,sos] then
  730.         blockread(f, darray[0], length, dw);
  731.     if dw <> length then halt(3);
  732.     case db of
  733.       dht  : do_dht (darray, length, hts);
  734.       dqt  : do_dqt (darray, length, qts);
  735.       sof0 : do_sof0(darray, length, f0);
  736.       sos  :
  737.       begin
  738.         do_sos (darray, length, si);
  739.         writeln('app0 information');
  740.         writeln('  version : ',ai.revision.major,'.',ai.revision.minor);
  741.         writeln('  xy_density units(0-2): ',ai.xy_density);
  742.         writeln('  x density : ',ai.x);
  743.         writeln('  y density : ',ai.y);
  744.         writeln('  thumb x : ',ai.thumb_x);
  745.         writeln('  thumb y : ',ai.thumb_y);
  746.  
  747.         writeln('sof0 information');
  748.         writeln('  precision : ',f0.precision);
  749.         writeln('  height : ',f0.image_height);
  750.         writeln('  width  : ',f0.image_width);
  751.         writeln('  number of components (1,3) :',byte(f0.comp_num));
  752.  
  753.  
  754.         close(f);
  755.         halt(1);
  756.       end;
  757.     end;
  758.   until false;
  759. end.
  760.